/* @flow */

import { cached, extend, toObject } from 'shared/util'

//该方法就是将'color:red;font-size:12px'形式的字符串转换为
//{color:'red', 'font-size':'12px'}形式的对象
export const parseStyleText = cached(function (cssText) {
  const res = {}
  //(?!...)：子表达式不能匹配右侧文本
  //该正则表达式的含义是：在';'字符之后存在闭合的小括号则就正确，比如：';(a)'、';a(a)'，
  //如果')'之前，';'之后不存在'('，则不匹配，比如';a)'
  //实际效果，比如style字符串的值为：'color:red;font-size:12px'，
  //结果为：['color:red','font-size:12px']，也就是使用';'进行分割。
  //@todo 不明白(?![^(]*\))的意义。
  const listDelimiter = /;(?![^(]*\))/g
  const propertyDelimiter = /:(.+)/
  cssText.split(listDelimiter).forEach(function (item) {
    if (item) {
      var tmp = item.split(propertyDelimiter)
      tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim())
    }
  })
  return res
})

// merge static and dynamic style data on the same vnode
function normalizeStyleData (data: VNodeData): ?Object {
  const style = normalizeStyleBinding(data.style)
  // static style is pre-processed into an object during compilation
  // and is always a fresh object, so it's safe to merge into it
  return data.staticStyle
    //动态style会覆盖静态style
    ? extend(data.staticStyle, style)
    : style
}

// normalize possible array / string values into Object
// 动态style支持的数据形式包括：
// 1）对象形式： :style="{color:hello, fontSize:world}"
// 2）对象数组形式： :style="[{color:hello, fontSize:world}, {position:yes}]"
// 3）字符串：:style="hello" data:{hello:'color:red;font-size:12px'}
export function normalizeStyleBinding (bindingStyle: any): ?Object {
  if (Array.isArray(bindingStyle)) {
    return toObject(bindingStyle)
  }
  if (typeof bindingStyle === 'string') {
    return parseStyleText(bindingStyle)
  }
  return bindingStyle
}

/**
 * parent component style should be after child's
 * so that parent component's style could override it
 * 该方法用于获得当前组件vnode的祖先vnode和子孙vnode的style的绑定结果，并将三者进行最后的合并，
 * 至于合并的顺序，看上方的英文注释。父级的style总会覆盖子级的style。
 */
export function getStyle (vnode: VNode, checkChild: boolean): Object {
  const res = {}
  let styleData

  //关于循环获得子和父组件的静态和动态style属性的原因，可查看platforms/web/util/class.js下的genClassForVnode
  //方法中的注释，class的处理与style的处理类似
  if (checkChild) {
    let childNode = vnode
    while (childNode.componentInstance) {
      childNode = childNode.componentInstance._vnode
      if (childNode.data && (styleData = normalizeStyleData(childNode.data))) {
        //先合并子孙vnode的style
        extend(res, styleData)
      }
    }
  }

  //然后合并当前vnode的style
  if ((styleData = normalizeStyleData(vnode.data))) {
    extend(res, styleData)
  }

  //最后合并祖先vnode的style
  //所以style的优先级是：父 > 子，动态style > 静态style
  let parentNode = vnode
  while ((parentNode = parentNode.parent)) {
    if (parentNode.data && (styleData = normalizeStyleData(parentNode.data))) {
      extend(res, styleData)
    }
  }
  return res
}

